package com.lzyh.thread;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;

import com.alibaba.fastjson.JSON;

/**
 * 多线程执行，两种方式都使用了CountDownLatch
 * 
 * @author lz10272
 * @version 2021-4-23 11:32:00
 */
public class ThreadClient {

	private Logger logger = LogManager.getLogger(getClass());

	public static void main(String[] args) {

	}

	private int threadCount = 5;
//	SingleThreadMethod thread = new SingleThreadMethod();

	@Test
	public void testExecutors() {
		CountDownLatch countDown = new CountDownLatch(threadCount);

//		ExecutorService executor = Executors.newFixedThreadPool(threadCount, Executors.defaultThreadFactory());
		ExecutorService executor = Executors.newFixedThreadPool(threadCount, new ZklThreadFactory());
		logger.info("threadCount-->>{}", threadCount);

		for (int i = 0; i < threadCount; i++) {
			SingleThreadMethod thread = new SingleThreadMethod();
			thread.setMyParam(String.valueOf(i));
			thread.setCountDown(countDown);
			executor.execute(thread);

		}

		// 等待处理完成
		try {
			countDown.await();
			logger.info("process successfully");
		} catch (InterruptedException e) {
			logger.error(e, e);
		}
		logger.info(String.format("isShutdown:%s, isTerminated:%s", executor.isShutdown(), executor.isTerminated()));
		executor.shutdown();
		logger.info(String.format("isShutdown:%s, isTerminated:%s", executor.isShutdown(), executor.isTerminated()));
	}

	@Test
	public void testThread() {
		logger.info(Thread.currentThread().getThreadGroup());
		CountDownLatch countDown = new CountDownLatch(threadCount);
		ThreadGroup threadGroup = new ThreadGroup("myThreadGroup");
		for (int i = 0; i < threadCount; i++) {
//			logger.info("i-->>" +i);

			SingleThreadMethod thread = new SingleThreadMethod();
			thread.setMyParam(String.valueOf(i));
			thread.setCountDown(countDown);

			Thread t = new Thread(threadGroup, thread, "myThreadPool-" + i);
//			t.setName("thread-" + i);
			t.start();
			monitorThreadOnce();
		}
		
//		monitorThreads();
		
		// 等待处理完成
		try {
			countDown.await();
			logger.info("process successfully");
		} catch (InterruptedException e) {
			logger.error(e, e);
		}
	}

	public void monitorThreads() {
		int i = 0;
		while (i<6) {
			Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();

			Set<Entry<Thread, StackTraceElement[]>> entrySet = allStackTraces.entrySet();
			for (Entry<Thread, StackTraceElement[]> entry : entrySet) {
				Thread thread = entry.getKey();
				StackTraceElement[] value = entry.getValue();
//				logger.info(JSON.toJSONString(allStackTraces));
				logger.info(String.format("threadName:%s, threadState:%s stackTraceElement:%s", thread.getName(), thread.getState(), JSON.toJSONString(value)));

			}
			
			i++;
			
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
			}
		}
		
	}
	
	private void monitorThreadOnce() {
		Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();

		Set<Entry<Thread, StackTraceElement[]>> entrySet = allStackTraces.entrySet();
		for (Entry<Thread, StackTraceElement[]> entry : entrySet) {
			Thread thread = entry.getKey();
			StackTraceElement[] value = entry.getValue();
//			logger.info(JSON.toJSONString(allStackTraces));
			logger.info(String.format("threadName:%s, threadState:%s stackTraceElement:%s", thread.getName(), thread.getState(), JSON.toJSONString(value)));

		}
	}

	
    /**
     * The default thread factory
     */
    static class ZklThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(0);
        private final String namePrefix;

        ZklThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "zklpool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
}
